package com.heiye.gateway.service;

import cn.dev33.satoken.stp.StpInterface;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.heiye.gateway.constant.RedisKeyConstants;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * @author: heiye
 * @date: 2024/09/23 下午4:01
 * @version: v1.0.0
 * @description: 自定义权限验证接口扩展
 */
@Slf4j
@Component
public class StpInterfaceService implements StpInterface {

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Resource
    private ObjectMapper objectMapper;

    /**
     * 获取角色权限
     *
     * @param userId
     * @param type
     * @return
     */
    @Override
    // 抛出任意异常
    @SneakyThrows
    public List<String> getPermissionList(Object userId, String type) {
        log.info("## 获取用户权限列表, userId: {}", userId);
        // 构建 用户-角色 redis key
        String roleKey = RedisKeyConstants.buildUserRoleKey(Long.valueOf(userId.toString()));

        // 根据用户 id ，从 redis 中获取该用户的角色集合
        String roleValue = redisTemplate.opsForValue().get(roleKey);

        // 校验
        if (StringUtils.isBlank(roleValue)) {
            return null;
        }

        // 将 JSON 字符串转换为 List<String> 角色集合
        List<String> roleKeys = objectMapper.readValue(roleValue, new TypeReference<>() {
        });

        // 校验
        if (CollUtil.isNotEmpty(roleKeys)) {
            // 查询这些角色对应的权限
            List<String> rolePermissionsKeys = roleKeys.stream()
                    .map(RedisKeyConstants::buildRolePermissionsKey)
                    .toList();

            // 通过 key 集合批量查询权限，提升查询性能, 得到权限列表
            List<String> rolePermissionsValues = redisTemplate.opsForValue().multiGet(rolePermissionsKeys);

            // 校验
            if (CollUtil.isNotEmpty(rolePermissionsValues)) {
                // 构建返回数据
                ArrayList<String> permissions = Lists.newArrayList();

                // 遍历所有角色的权限集合，统一添加到 permissions 集合中
                rolePermissionsValues.forEach(value -> {
                    try {
                        // 将 json 字符串转换为 List<String> 权限集合
                        List<String> rolePermissions = objectMapper.readValue(value, new TypeReference<>() {
                        });

                        // 将里面的 rolePermission 添加到 permissions中
                        permissions.addAll(rolePermissions);

                    } catch (JsonProcessingException e) {
                        log.error("==> json 解析错误: ", e);
                    }
                });

                // 返回此用户所拥有的权限
                return permissions;
            }
        }
        return null;
    }

    /**
     * 获取用户角色
     *
     * @param userId
     * @param type
     * @return
     */
    @Override
    @SneakyThrows
    public List<String> getRoleList(Object userId, String type) {
        log.info("## 获取用户角色列表, userId: {}", userId);

        // 构建 用户-角色 redis key
        String roleKey = RedisKeyConstants.buildUserRoleKey(Long.valueOf(userId.toString()));

        // 根据用户 id ，从 redis 中获取该用户的角色集合
        String roleValue = redisTemplate.opsForValue().get(roleKey);

        // 校验
        if (StringUtils.isBlank(roleValue)) {
            return null;
        }

        // 将 json 字符串转换为 List<String> 集合
        return objectMapper.readValue(roleValue, new TypeReference<>() {
        });
    }
}
